package com.file.parser.socialsecurity;

import com.file.bo.ResponseData;
import com.file.bo.socialsecurity.HubeiIndividualRecordSheet;
import com.file.bo.socialsecurity.HubeiInsuranceParticipation;
import com.file.constant.ErrorCode;
import com.file.parser.BasePdfParser;
import com.file.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import technology.tabula.*;
import technology.tabula.detectors.SpreadsheetDetectionAlgorithm;
import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;

import java.io.File;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 湖北省武汉市电子社保pdf解析
 * @author anyspa
 */

@Slf4j
public class HubeiSocialSecurityPdfParser extends BasePdfParser {

    public ResponseData<String> parseHubeiSocialSecurityPdfToJson(String daId, String filePath) {
        log.info("parseHubeiSocialSecurityPdfToJson started, daId:{}", daId);
        String json = null;

        try {
            if (filePath.contains("cbzm")) {
                HubeiInsuranceParticipation hubeiInsuranceParticipation = parseHubeiInsuranceParticipation(filePath);
                json = JsonUtils.convertObjectToJson(hubeiInsuranceParticipation);
            } else if (filePath.contains("qyd")) {
                HubeiIndividualRecordSheet hubeiIndividualRecordSheet = parseHubeiIndividualRecordSheet(filePath);
                json = JsonUtils.convertObjectToJson(hubeiIndividualRecordSheet);
            } else {
                log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseHubeiSocialSecurityPdfToJson failed, new type not supported");
                return new ResponseData<>(null, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
            }
        } catch (Exception e) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseHubeiSocialSecurityPdfToJson failed", e);
            return new ResponseData<>(null, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
        }

        log.info("parseHubeiSocialSecurityPdfToJson completed, daId:{}", daId);
        return new ResponseData<>(json, ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg());
    }

    private HubeiInsuranceParticipation parseHubeiInsuranceParticipation(String filePath) {
        HubeiInsuranceParticipation hubeiInsuranceParticipation = parseInsuranceParticipationHeader(filePath);
        Map<Integer, List<List<String>>> rowMap = parseFileToRowList(filePath);
        List<List<String>> rowList = new ArrayList<>();
        rowMap.values().forEach(rowList::addAll);
        parseListToBO(rowList, hubeiInsuranceParticipation);

        return hubeiInsuranceParticipation;
    }

    private HubeiInsuranceParticipation parseInsuranceParticipationHeader(String filePath) {
        HubeiInsuranceParticipation hubeiInsuranceParticipation = new HubeiInsuranceParticipation();
        String text = parsePdfHeaderText(filePath);
        String comment = text.substring(text.indexOf("备注：") + 3, text.indexOf("打印时间"));
        String printTime = text.substring(text.indexOf("打印时间：") + 5, text.lastIndexOf("第"));

        hubeiInsuranceParticipation.setComment(comment);
        hubeiInsuranceParticipation.setPrintTime(printTime);
        return hubeiInsuranceParticipation;
    }

    private HubeiIndividualRecordSheet parseHubeiIndividualRecordSheet(String filePath) {
        HubeiIndividualRecordSheet hubeiIndividualRecordSheet = parseIndividualRecordSheetHeader(filePath);
        Map<Integer, List<List<String>>> rowMap = parseFileToRowList(filePath);
        parseListToBO(rowMap, hubeiIndividualRecordSheet);

        return hubeiIndividualRecordSheet;
    }

    private HubeiIndividualRecordSheet parseIndividualRecordSheetHeader(String filePath) {
        HubeiIndividualRecordSheet hubeiIndividualRecordSheet = new HubeiIndividualRecordSheet();
        String pdfHeader = parsePdfHeaderText(filePath);
        Pattern pattern = Pattern.compile("(\\d{4}|--)年(\\d{2}|--)月至(\\d{4}|--)年(\\d{2}|--)月");
        Matcher matcher = pattern.matcher(pdfHeader);
        if (matcher.find()) {
            hubeiIndividualRecordSheet.setRecordPeriod(matcher.group());
        }
        String printTime = pdfHeader.substring(pdfHeader.indexOf("打印时间：") + 5).trim();
        hubeiIndividualRecordSheet.setPrintTime(printTime);
        return hubeiIndividualRecordSheet;
    }

    private void parseListToBO(List<List<String>> rowList, HubeiInsuranceParticipation hubeiInsuranceParticipation) {
        String sectionName = "";
        List<HubeiInsuranceParticipation.InsuranceParticipationRecord> insuranceParticipationRecordList = new ArrayList<>();

        for (List<String> cellList : rowList) {
            if (StringUtils.equals(cellList.get(0), "姓名")) {
                sectionName = "参保人姓名";
            } else if (StringUtils.equals(cellList.get(0), "参保缴费地")) {
                sectionName = "参保缴费地";
            } else if (StringUtils.equals(cellList.get(0), "缴费地最末所在单位")) {
                sectionName = "缴费地最末所在单位";
                continue;
            } else if (StringUtils.contains(cellList.get(0), "参保缴费情况")) {
                sectionName = "参保缴费情况";
                continue;
            } else if (StringUtils.equals(cellList.get(0), "记录月份")) {
                continue;
            }

            switch (sectionName) {//NOSONAR
                case "参保人姓名":
                    hubeiInsuranceParticipation.setName(cellList.get(1));
                    hubeiInsuranceParticipation.setGender(cellList.get(3));
                    hubeiInsuranceParticipation.setPersonalNumber(cellList.get(5));
                    hubeiInsuranceParticipation.setSocialSecurityNumber(cellList.get(7));
                    break;
                case "参保缴费地":
                    hubeiInsuranceParticipation.setInsurancePaymentLocation(cellList.get(1));
                    hubeiInsuranceParticipation.setLocalPaymentMonths(cellList.get(3));
                    hubeiInsuranceParticipation.setTypesOfInsurance(cellList.get(5));
                    break;
                case "缴费地最末所在单位":
                    HubeiInsuranceParticipation.UnitOfLastPaymentPlace unitOfLastPaymentPlace
                            = new HubeiInsuranceParticipation.UnitOfLastPaymentPlace();
                    unitOfLastPaymentPlace.setUnitNo(cellList.get(1));
                    unitOfLastPaymentPlace.setUnitName(cellList.get(3));
                    hubeiInsuranceParticipation.setUnitOfLastPaymentPlace(unitOfLastPaymentPlace);
                    break;
                case "参保缴费情况":
                    if (StringUtils.isNotBlank(cellList.get(0))) {
                        HubeiInsuranceParticipation.InsuranceParticipationRecord insuranceParticipationRecord
                                = new HubeiInsuranceParticipation.InsuranceParticipationRecord();
                        insuranceParticipationRecord.setRecordMonth(cellList.get(0));
                        insuranceParticipationRecord.setUnitName(cellList.get(1));
                        insuranceParticipationRecord.setPaymentBase(cellList.get(2));
                        insuranceParticipationRecord.setPaymentType(cellList.get(3));
                        insuranceParticipationRecordList.add(insuranceParticipationRecord);
                    }

                    if (StringUtils.isNotBlank(cellList.get(4))) {
                        HubeiInsuranceParticipation.InsuranceParticipationRecord insuranceParticipationRecord
                                = new HubeiInsuranceParticipation.InsuranceParticipationRecord();
                        insuranceParticipationRecord.setRecordMonth(cellList.get(4));
                        insuranceParticipationRecord.setUnitName(cellList.get(5));
                        insuranceParticipationRecord.setPaymentBase(cellList.get(6));
                        insuranceParticipationRecord.setPaymentType(cellList.get(7));
                        insuranceParticipationRecordList.add(insuranceParticipationRecord);
                    }
                    break;
            }
        }
        List<HubeiInsuranceParticipation.InsuranceParticipationRecord> insuranceParticipationRecords = insuranceParticipationRecordList
                        .stream()
                        .sorted(Comparator.comparing(HubeiInsuranceParticipation.InsuranceParticipationRecord::getRecordMonth).reversed())
                        .collect(Collectors.toList());

        hubeiInsuranceParticipation.setInsuranceParticipationRecordList(insuranceParticipationRecords);
    }

    private void parseListToBO(Map<Integer, List<List<String>>> rowMap, HubeiIndividualRecordSheet hubeiIndividualRecordSheet) {
        String sectionName = "";
        HubeiIndividualRecordSheet.PersonBaseInfo personBaseInfo = new HubeiIndividualRecordSheet.PersonBaseInfo();
        HubeiIndividualRecordSheet.PaymentInfo paymentInfo = new HubeiIndividualRecordSheet.PaymentInfo();
        HubeiIndividualRecordSheet.BasicPension basicPension = new HubeiIndividualRecordSheet.BasicPension();

        // 解析pdf第一页的表格
        for (int i = 0; i < rowMap.get(1).size(); i++) {
            List<String> cellList = rowMap.get(1).get(i);
            if (StringUtils.equals(cellList.get(0), "姓名")) {
                sectionName = "姓名";
            } else if (StringUtils.equals(cellList.get(0), "首次参保日期")) {
                sectionName = "首次参保日期";
                continue;
            } else if (StringUtils.equalsAny(cellList.get(0), "个人月缴费基数")) {
                sectionName = "个人月缴费基数";
                continue;
            } else if (StringUtils.equalsAny(cellList.get(0), "本年个人补缴欠费金额")) {
                sectionName = "本年个人补缴欠费金额";
                continue;
            } else if (StringUtils.equalsAny(cellList.get(0), "截至上年末个人账户累计储存额")) {
                sectionName = "截至上年末个人账户累计储存额";
                continue;
            } else if (StringUtils.equalsAny(cellList.get(0), "养老", "缴费情况", "个人账户情况", "基本养老保险")) {
                continue;
            }

            switch (sectionName) {//NOSONAR
                case "姓名" :
                    personBaseInfo.setName(cellList.get(1));
                    personBaseInfo.setUnitName(cellList.get(3));
                    personBaseInfo.setSocialSecurityNumber(cellList.get(5));
                    break;
                case "首次参保日期" :
                    HubeiIndividualRecordSheet.FirstEnrollmentDate firstEnrollmentDate
                            = new HubeiIndividualRecordSheet.FirstEnrollmentDate();
                    firstEnrollmentDate.setPension(cellList.get(4));
                    firstEnrollmentDate.setMedical(cellList.get(5));
                    firstEnrollmentDate.setUnemployment(cellList.get(6));
                    firstEnrollmentDate.setInjury(cellList.get(7));
                    firstEnrollmentDate.setFertility(cellList.get(8));
                    personBaseInfo.setFirstEnrollmentDate(firstEnrollmentDate);
                    break;
                case "个人月缴费基数" :
                    HubeiIndividualRecordSheet.PersonalPaymentBase personalPaymentBase
                            = new HubeiIndividualRecordSheet.PersonalPaymentBase();
                    personalPaymentBase.setPension(cellList.get(0));
                    personalPaymentBase.setMedical(cellList.get(1));
                    personalPaymentBase.setUnemployment(cellList.get(2));
                    personalPaymentBase.setInjury(cellList.get(3));
                    personalPaymentBase.setFertility(cellList.get(4));
                    paymentInfo.setPersonalPaymentBase(personalPaymentBase);

                    HubeiIndividualRecordSheet.PensionPaymentInfo pensionPaymentInfo
                            = new HubeiIndividualRecordSheet.PensionPaymentInfo();
                    pensionPaymentInfo.setCompanyPays(cellList.get(5));
                    pensionPaymentInfo.setPersonalPays(cellList.get(6));
                    paymentInfo.setPensionPaymentInfo(pensionPaymentInfo);

                    HubeiIndividualRecordSheet.MedicalPaymentInfo medicalPaymentInfo
                            = new HubeiIndividualRecordSheet.MedicalPaymentInfo();
                    medicalPaymentInfo.setCompanyPays(cellList.get(7));
                    medicalPaymentInfo.setPersonalPays(cellList.get(8));
                    paymentInfo.setMedicalPaymentInfo(medicalPaymentInfo);

                    HubeiIndividualRecordSheet.UnemploymentPaymentInfo unemploymentPaymentInfo
                            = new HubeiIndividualRecordSheet.UnemploymentPaymentInfo();
                    unemploymentPaymentInfo.setCompanyPays(cellList.get(9));
                    unemploymentPaymentInfo.setPersonalPays(cellList.get(10));
                    paymentInfo.setUnemploymentPaymentInfo(unemploymentPaymentInfo);

                    paymentInfo.setInjuryPaymentInfo(cellList.get(11));
                    paymentInfo.setFertilityPaymentInfo(cellList.get(12));
                    break;
                case "本年个人补缴欠费金额" :
                    HubeiIndividualRecordSheet.IndividualsPaidArrears individualsPaidArrears
                            = new HubeiIndividualRecordSheet.IndividualsPaidArrears();
                    individualsPaidArrears.setPension(cellList.get(0));
                    individualsPaidArrears.setMedical(cellList.get(1));
                    individualsPaidArrears.setUnemployment(cellList.get(2));
                    paymentInfo.setIndividualsPaidArrears(individualsPaidArrears);

                    HubeiIndividualRecordSheet.NumberOfPaymentMonths numberOfPaymentMonths
                            = new HubeiIndividualRecordSheet.NumberOfPaymentMonths();
                    numberOfPaymentMonths.setPension(cellList.get(3));
                    numberOfPaymentMonths.setMedical(cellList.get(4));
                    numberOfPaymentMonths.setUnemployment(cellList.get(5));
                    paymentInfo.setNumberOfPaymentMonths(numberOfPaymentMonths);

                    HubeiIndividualRecordSheet.NumberOfActualPaymentMonths numberOfActualPaymentMonths
                            = new HubeiIndividualRecordSheet.NumberOfActualPaymentMonths();
                    numberOfActualPaymentMonths.setPension(cellList.get(6));
                    numberOfActualPaymentMonths.setMedical(cellList.get(7));
                    numberOfActualPaymentMonths.setUnemployment(cellList.get(8));
                    paymentInfo.setNumberOfActualPaymentMonths(numberOfActualPaymentMonths);

                    HubeiIndividualRecordSheet.AccumulatedUnpaidMonths accumulatedUnpaidMonths
                            = new HubeiIndividualRecordSheet.AccumulatedUnpaidMonths();
                    accumulatedUnpaidMonths.setPension(cellList.get(9));
                    accumulatedUnpaidMonths.setMedical(cellList.get(10));
                    accumulatedUnpaidMonths.setUnemployment(cellList.get(11));
                    paymentInfo.setAccumulatedUnpaidMonths(accumulatedUnpaidMonths);

                    break;
                case "截至上年末个人账户累计储存额" :
                    basicPension.setAccumulatedSavingsInPersonalAccountsLastYear(cellList.get(0));
                    basicPension.setCurrentAccountAmount(cellList.get(1));
                    basicPension.setAmountOfPersonalAccountDisbursementsThisYear(cellList.get(2));
                    basicPension.setCurrentRecordedInterest(cellList.get(3));
                    basicPension.setAccumulatedSavingsInPersonalAccountsThisYear(cellList.get(4));
                    break;
            }
        }

        if (rowMap.size() > 1) {
            sectionName = "";
            // 解析pdf第二页的表格
            for (int i = 0; i < rowMap.get(2).size(); i++) {
                List<String> cellList = rowMap.get(2).get(i);
                if (StringUtils.equals(cellList.get(0), "首次参保日期")) {
                    sectionName = "首次参保日期";
                    continue;
                } else if (StringUtils.equalsAny(cellList.get(0), "个人月缴费基数")) {
                    sectionName = "个人月缴费基数";
                    continue;
                } else if (StringUtils.equalsAny(cellList.get(0), "工伤保险待遇享受情况")) {
                    sectionName = "工伤保险待遇享受情况";
                    continue;
                } else if (StringUtils.equalsAny(cellList.get(0), "本年个人补缴欠费金额")) {
                    sectionName = "本年个人补缴欠费金额";
                    continue;
                } else if (StringUtils.equalsAny(cellList.get(0), "姓名", "养老", "缴费情况", "工伤保险待遇享受情况",
                        "工伤保险待遇享受开始年月")) {
                    continue;
                }

                switch (sectionName) {//NOSONAR
                    case "首次参保日期" :
                        HubeiIndividualRecordSheet.FirstEnrollmentDate firstEnrollmentDate
                                = personBaseInfo.getFirstEnrollmentDate();
                        // 城镇职工失业表
                        if (StringUtils.isBlank(firstEnrollmentDate.getUnemployment()) || StringUtils.contains(firstEnrollmentDate.getUnemployment(), "--")) {
                            firstEnrollmentDate.setUnemployment(cellList.get(4));
                        }
                        // 城镇职工工伤表
                        if (StringUtils.isBlank(firstEnrollmentDate.getInjury()) || StringUtils.contains(firstEnrollmentDate.getInjury(), "--")) {
                            firstEnrollmentDate.setInjury(cellList.get(7));
                        }
                        break;
                    case "个人月缴费基数" :
                        // 城镇职工工伤表
                        HubeiIndividualRecordSheet.PersonalPaymentBase personalPaymentBase
                                = paymentInfo.getPersonalPaymentBase();
                        if (StringUtils.isBlank(personalPaymentBase.getInjury()) || StringUtils.contains(personalPaymentBase.getInjury(), "--")) {
                            personalPaymentBase.setInjury(cellList.get(3));
                        }
                        paymentInfo.setInjuryPaymentInfo(cellList.get(11));
                        break;
                    case "本年个人补缴欠费金额" :
                        // 城镇职工失业表
                        HubeiIndividualRecordSheet.IndividualsPaidArrears individualsPaidArrears
                                = paymentInfo.getIndividualsPaidArrears();
                        if (StringUtils.isBlank(individualsPaidArrears.getUnemployment()) || StringUtils.contains(individualsPaidArrears.getUnemployment(), "-")) {
                            individualsPaidArrears.setUnemployment(cellList.get(2));
                        }

                        HubeiIndividualRecordSheet.NumberOfPaymentMonths numberOfPaymentMonths
                                = paymentInfo.getNumberOfPaymentMonths();
                        if (StringUtils.isBlank(numberOfPaymentMonths.getUnemployment()) || StringUtils.contains(numberOfPaymentMonths.getUnemployment(), "-")) {
                            numberOfPaymentMonths.setUnemployment(cellList.get(5));
                        }

                        HubeiIndividualRecordSheet.NumberOfActualPaymentMonths numberOfActualPaymentMonths
                                = paymentInfo.getNumberOfActualPaymentMonths();
                        if (StringUtils.isBlank(numberOfActualPaymentMonths.getUnemployment()) || StringUtils.contains(numberOfActualPaymentMonths.getUnemployment(), "-")) {
                            numberOfActualPaymentMonths.setUnemployment(cellList.get(8));
                        }

                        HubeiIndividualRecordSheet.AccumulatedUnpaidMonths accumulatedUnpaidMonths
                                = paymentInfo.getAccumulatedUnpaidMonths();
                        if (StringUtils.isBlank(accumulatedUnpaidMonths.getUnemployment()) || StringUtils.contains(accumulatedUnpaidMonths.getUnemployment(), "-")) {
                            accumulatedUnpaidMonths.setUnemployment(cellList.get(11));
                        }

                        break;
                }
            }
        }
        hubeiIndividualRecordSheet.setPersonBaseInfo(personBaseInfo);
        hubeiIndividualRecordSheet.setPaymentInfo(paymentInfo);
        hubeiIndividualRecordSheet.setBasicPension(basicPension);
    }

    private Map<Integer, List<List<String>>> parseFileToRowList(String filePath) {
        // 1. 读取文件
        File pdf = new File(filePath);

        //页面所有table的记录，每一个元素代表下面一条记录cellList
        Map<Integer, List<List<String>>> rowMap = new HashMap<>();

        // 2. pdfbox读取PDDocument
        try (PDDocument pdfDocument = PDDocument.load(pdf)) {
            // 3. tabula新建ObjectExtractor和NurminenDetectionAlgorithm，同时准备接收表格Rectangle的结构
            ObjectExtractor objectExtractor = new ObjectExtractor(pdfDocument);
            SpreadsheetDetectionAlgorithm detectionAlgorithm = new SpreadsheetDetectionAlgorithm();
            Map<Integer, List<Rectangle>> pageNumber2RectangleListMap = new HashMap<>();//key为页的序号， value为对应的Rectangle的list

            // 4. 获取每页的PageIterator
            PageIterator pageIterator = objectExtractor.extract();

            // 5. 解析每页的Rectangle
            // 如果单页pdf中有多个Rectangle，则解析出来的List<Rectangle>会有多个对象
            while (pageIterator.hasNext()) {
                Page page = pageIterator.next();
                List<Rectangle> rectangleList = detectionAlgorithm.detect(page);
                if (rectangleList.size() > 0) {
                    pageNumber2RectangleListMap.put(page.getPageNumber(), rectangleList);
                }
            }

            // 6.通过table位置获取表格具体内容
            SpreadsheetExtractionAlgorithm extractionAlgorithm = new SpreadsheetExtractionAlgorithm();

            // 如果单页pdf中有多个表格，则解析出来的List<Rectangle>会有多个对象
            for (Map.Entry<Integer, List<Rectangle>> entry : pageNumber2RectangleListMap.entrySet()) {
                List<List<String>> rowList = new ArrayList<>();
                Page page = objectExtractor.extract(entry.getKey());

                List<Rectangle> rectangleList = entry.getValue();
                for (Rectangle rectangle : rectangleList) {
                    if (Double.compare(rectangle.getHeight(), 0.0) == 0) {
                        continue;
                    }
                    rectangle.setBottom(rectangle.getBottom() + 10);
                    Page area = page.getArea(rectangle);
                    // 如果每页有多个表格，解析每一个table
                    List<Table> tableList = extractionAlgorithm.extract(area);
                    for (Table table : tableList) {
                        for (int i = 0; i < table.getRowCount(); i++) {
                            List<String> cellList = new ArrayList<>();//一条记录，每个单元格占一个元素
                            for (int j = 0; j < table.getColCount(); j++) {
                                cellList.add(table.getCell(i, j).getText(false));
                            }
                            rowList.add(cellList);
                        }
                    }
                    rowMap.put(page.getPageNumber(), rowList);
                }

            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }

        return rowMap;
    }

    public static void main(String[] args) {
        String filePath = "D:\\data\\file\\socialsecurity\\湖北省参保证明_cbzm.pdf";
        String json;
        HubeiSocialSecurityPdfParser hubeiSocialSecurityPdfParser = new HubeiSocialSecurityPdfParser();
        json = hubeiSocialSecurityPdfParser.parseHubeiSocialSecurityPdfToJson("", filePath).getData();
        System.out.println(json);

        filePath = "D:\\data\\file\\socialsecurity\\湖北省个人权益单_qyd.pdf";
        json = hubeiSocialSecurityPdfParser.parseHubeiSocialSecurityPdfToJson("", filePath).getData();
        System.out.println(json);

        filePath = "D:\\data\\file\\socialsecurity\\hubei_chengxiang_cbzm.pdf";
        json = hubeiSocialSecurityPdfParser.parseHubeiSocialSecurityPdfToJson("", filePath).getData();
        System.out.println(json);
    }
}
